<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>algorithm_test</title>
</head>

<body>

<?php
	// decode table
	$indexTable = array("A"=>0,"B"=>1,"C"=>2,"D"=>3,"E"=>4,"F"=>5,"G"=>6,"H"=>7,"I"=>8,
		"J"=>9,"K"=>10,"L"=>11,"M"=>12,"N"=>13,"O"=>14,"P"=>15,"Q"=>16,"R"=>17,"S"=>18,
		"T"=>19,"U"=>20,"V"=>21,"W"=>22,"X"=>23,"Y"=>24,"Z"=>25,"a"=>26,"b"=>27,"c"=>28,
		"d"=>29,"e"=>30,"f"=>31,"g"=>32,"h"=>33,"i"=>34,"j"=>35,"k"=>36,"l"=>37,"m"=>38,
		"n"=>39,"o"=>40,"p"=>41,"q"=>42,"r"=>43,"s"=>44,"t"=>45,"u"=>46,"v"=>47,"w"=>48,
		"x"=>49,"y"=>50,"z"=>51,"0"=>52,"1"=>53,"2"=>54,"3"=>55,"4"=>56,"5"=>57,"6"=>58,
		"7"=>59,"8"=>60,"9"=>61);
		
	class ExtBase64Compression {
		private $encode_string;
		private $decode_string;
		
		private $index_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
		
		// convert to Unicode xxxx
		function UTF8ToUnicode($str) {
			$unicode_str = "";
			$str_length = strlen($str);
			
			for ($i = 0; $i < $str_length; $i += 9) {
				$str1 = hexdec(substr($str, $i + 1, 2)) & 0x0F;
				$str2 = hexdec(substr($str, $i + 4, 2)) & 0x3F;
				$str3 = hexdec(substr($str, $i + 7, 2)) & 0x3F;
				
				$dec_str = ($str1 << 12) | ($str2 << 6) | $str3;
				
				$unicode_str .= dechex($dec_str); 
			}
			
			return $unicode_str;
		}

		function compress($str) {
			$this->encode_string = "";
			
			$utf8_str = urlencode($str);
			// echo $str."<br />".$utf8_str."<br />";
			
			$php_encode_str = $this->UTF8ToUnicode($utf8_str);
			// echo strlen($php_encode_str)." ".$php_encode_str."<br />";
			
			$str_length = strlen($php_encode_str);
			//echo $str_length."<br />";
			
			for ($i = 0; $i < $str_length; $i += 4) {
				
				$sub_str = substr($php_encode_str, $i, 4);
				
				$bin_str = hexdec($sub_str) << 2;
				
				if (($bin_str & 0x00F80) == 0x00F80) {
					$bin_str = ($bin_str & 0xFFDFF) | 0x00001;
				}
				
				//0x3F 0011 1111
				$num_3 = $bin_str & 0x0003F;
				//0xFC0 1111 1100 0000
				$num_2 = ($bin_str & 0x0FC0) >> 6;
				// 0x3F000 0011 1111 0000 0000 0000
				$num_1 = ($bin_str & 0x3F000) >> 12;
				
				// echo 'num_1 = '.$num_1." num2 = ".$num_2." num3 = ".$num_3."<br />";
				
				$str_1 = $this->index_table[$num_1];
				$str_2 = $this->index_table[$num_2];
				$str_3 = $this->index_table[$num_3];
				//echo 'num_1 = '.$str_1." num2 = ".$str_2." num3 = ".$str_3."<br />";
				$encode_string.= $str_1.$str_2.$str_3;
			}
			// echo strlen($encode_string)." ".$encode_string."<br />";
			return $encode_string;
		}
		
		function decompress($encodeStr) {
			$unicode = "";
			$offset = array(0xF000, 0x0F00, 0x00F0, 0x000F);
			$hexArray = array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F");
			
			//echo $encodeStr." ".strlen($encodeStr)."<br />";
			
			for ($i = 0; $i < strlen($encodeStr); ++$i) {
				if ($encodeStr[$i] == '$') {
					++$i;
					$unicode .= substr($encodeStr, $i, 1);
				} else {
					$utf8 = "";
					$subStr = substr($encodeStr, $i, 3);
					
					$i += 2;
					// 获得编码值
					$extValue = ($GLOBALS['indexTable'][$subStr[0]] << 12) | ($GLOBALS['indexTable'][$subStr[1]] << 6)
						| ($GLOBALS['indexTable'][$subStr[2]]);
					
					// echo decbin($extValue)."<br />";
					// 还原Unicode值
					if ($extValue & 0x1) {
						$extValue = ($extValue | 0x200) & 0xFFFFE;
					}
					
					$extValue = $extValue >> 2;
					
					
					// 获取各个字符
					for ($j = 0; $j < 4; ++$j) {
						$hexIndex = ($extValue & $offset[$j]) >> (12 - 4 * $j);
						$utf8 .= $hexArray[$hexIndex];
					}
					
					// 将中文转化为utf8编码
					$unicode .= $this->UCSToUTF8($utf8);
				}
			}
			
			//return $unicode;
			$utf8 = urldecode($unicode);
			return $utf8;
		}
		
		// convert to utf8 encode
		function UCSToUTF8($unicode) {
			// 获取其十六进制值
			$ucs = hexdec($unicode);
			// ASCII码
			if ($ucs < 0x80) {
					$utf8 = ucs & 0x7F;
			} else if ($ucs > 0x7F && $ucs < 0x800) {
				$lowByte = 0x80 | ($ucs & 0x3F);
				$highByte = 0xC0 | (($ucs & 0x7C0) >> 6);
				
				$utf8 = ($highByte << 8 | $lowByte);
			} else if ($ucs > 0x7FF && $ucs < 0x10000) {
				$lowByte = 0x80 | ($ucs & 0x3F);
				$midByte = 0x80 | (($ucs & 0xFC0) >> 6);
				$highByte = 0xE0 | (($ucs & 0xF000) >> 12);
				
				$utf8 = ($highByte << 16) | ($midByte << 8) | $lowByte;
			} else {
				// 不支持大于0x10000的Unicode值
				echo "don't support";
			}
		
			$utf8 = dechex($utf8);
			$result = "";
			for ($i = 0; $i < strlen($utf8); $i = $i + 2) {
				$result .= ("%".substr($utf8, $i, 2));
			}
			return $result;
		}
	}
?>

<?
	class FileOperator {
		// 读文件
		function read_file($file_name) {
			$file_szie = filesize($file_name);
			$file = fopen($file_name, "r");
			$file_content = fread($file, $file_szie);
			fclose($file);
			return $file_content;
		}
		
		// 写文件
		function write_file($file_name, $file_content) {
			$file = fopen($file_name, "w");
			fwrite($file, $file_content);
			fclose($file);
		}
		
		// 判断两个文本文件是否一样
		function is_the_same($file_name1, $file_name2) {
			$file_szie1 = filesize($file_name1);
			$file1 = fopen($file_name1, "r");
			$file_content1 = fread($file1, $file_szie1);
			// echo $file_content1."<br />";
			fclose($file1);
			
			$file_szie2 = filesize($file_name2);
			$file2 = fopen($file_name2, "r");
			$file_content2 = fread($file2, $file_szie2);
			// echo $file_content2."<br />";
			fclose($file2);
			
			$file_content1 = substr($file_content1, 3, strlen($file_content1));
			
			// echo $file_content1."<br />".$file_content2."<br>";
			$len1 = strlen($file_content1);
			$len2 = strlen($file_content2);
			
			for ($i = 0; $i < $len1; $i += 3) {
				$sub_1 = substr($file_content1, $i, 3);
				$sub_2 = substr($file_content2, $i, 3);
				
				if ($sub_1 != $sub_2) {
					echo 'i = '.$i.' sub_1 = '.$sub_1.' sub_2 = '.$sub_2."<br />";
				}
			}
			
			echo $len1." ".$len2."<br />";
			
			if ($file_content1 == $file_content2) return 1;
			else return 0;
		}
	}
?>

<?
	$fp = new FileOperator();
	$test = new ExtBase64Compression();
	
	// 时间转换
	function process_time($string_time) {
		$msec = substr($string_time, 0, 10);
		$sec = substr($string_time, 11, 10);
		
		return ($sec % 100) + $msec;
	} 
	
	// 测试编码解码的正确性
	function test_right() {
		$test_str = "碴";
		$encode_str = $GLOBALS['test']->compress($test_str);
		$decode_str = $GLOBALS['test']->decompress($encode_str);
	
		echo $test_str."<br />".$encode_str."<br />".$decode_str."<br />";
	}
	// test_right();
	
	// 生成带测试的编码数据
	function generate_encode() {
		$test_data = $GLOBALS['fp']->read_file("./test/t_1000.txt");
		//echo $test_data."<br />";
		
		$urlencode_str = urlencode($test_data);
		$encode_str = $GLOBALS['test']->compress($test_data);
		// Unicode存储占用四个字节
		$encode_str = substr($encode_str, 2, strlen($encode_str));
		// echo $encode_str."<br />";
		
		$GLOBALS['fp']->write_file("./test/t_1000_ue.txt", $urlencode_str);
		$GLOBALS['fp']->write_file("./test/t_1000_e.txt", $encode_str);
		
		// echo "Successful generate the code!<br />";
	}
	
	generate_encode();
	
	// 测试服务器解码需要的时间
	function test_decode() {
		// test algorithm time spend
		echo "<b>This is decompress test:</b><br />";
		
		$t_before_read = process_time(microtime());
		echo $t_before_read." "."Read data begin"."<br />";
		$test_data = $GLOBALS['fp']->read_file("./test/t_1000_e.txt");
		$t_after_read = process_time(microtime());
		//echo $test_data."<br />";
		echo $t_after_read." "."Read data finished!"."<br />";
		
		$t_before_decode = process_time(microtime());
		echo $t_before_decode." "."Decode data begin!"."<br />";
		$decode_data = $GLOBALS['test']->decompress($test_data);
		$t_after_decode = process_time(microtime());
		echo $t_after_decode." "."Decode data finished!"."<br />";
		
		$GLOBALS['fp']->write_file("./test/t_1000de.txt", $decode_data);
		
		echo "decompress cost time: ".($t_after_decode - $t_before_decode)."<br />";
		
		
		// test urlencode time spend
		echo "<br><b>This is urldecode test:</b><br />";
		
		$t_before_read = process_time(microtime());
		
		echo $t_before_read." "."Read data begin!"."<br />";
		$test_data = $GLOBALS['fp']->read_file("./test/t_1000_ue.txt");
		$t_after_read = process_time(microtime());
		echo $t_after_read." "."Read data finished!"."<br />";
		
		$t_before_decode = process_time(microtime());
		echo $t_before_decode." "."Decode data begin!"."<br />";
		$decode_data = urldecode($test_data);
		$t_after_decode = process_time(microtime());
		echo $t_after_decode." "."Decode data finished!"."<br />";
		
		$GLOBALS['fp']->write_file("./test/t_1000ude.txt", $decode_data);
		
		echo "urldecode cost time: ".($t_after_decode - $t_before_decode)."<br />";
		
		
		// 测试两个文件时否一样并找出不同之处
		/*
		$file_1 = "./test/t_500000.txt";
		$file_2 = "./test/t_500000de.txt";
		
		if ($GLOBALS['fp']->is_the_same($file_1, $file_2)) {
			echo "The same!"."<br />";
		} else {
			echo "Difference!"."<br />";
		}
		*/
	}
	test_decode();
	
?>
</body>
</html>